This paper describes IRIS ViewKit , a C++ application framework designed to simplify the task of developing applications based on the OSF/Motif(tm)user interface toolkit(1). IRIS ViewKit framework promotes consistency by providing a common architecture for applications and improves programmer productivity by providing high-level, and in many cases automatic, support for commonly-needed operations. In addition to providing facilities normally associated with a graphical user interface, the framework serves as a central integration platform for other facilities applications typically need. These include support for inter-application communication, integration with the Silicon Graphics Indigo Magic desktop, and automatic on-line context-sensitive help. The IRIS ViewKit framework is currently in wide use within Silicon Graphics and serves as the basis of all CASEVision(tm) software development products, the IRIS InSight(tm) on-line documentation product, the Indigo Magic(tm) Desktop, the InPerson(tm) desktop conferencing system, and many other products. IRIS ViewKit can also be used with the IRIS Inventor(tm) library, which is based in part on the ViewKit model.
In recent years, applications with interactive user interfaces have become more difficult to develop because the expectations placed on such applications have grown dramatically. An application was once considered "user friendly" if it provided a row of mouse-selectable buttons instead of, or in addition to, a command-line interface. Today, applications are expected to conform to much higher standards of excellence. Good contemporary user interfaces provide features such as context-sensitive on-line help, support error recoverability, provide the ability to undo the application's most recent actions, and so on. Contemporary interfaces may involve hundreds of user interface widgets, and support multiple real-time views of various types of underlying information. With new advances in hardware, modern applications routinely support audio, integrated video, and even speech input. Applications are generally integrated with a desktop manager, provide drag-and-drop interfaces, and support inter-application communication and data exchange. Combining these pieces to create a complete application stretches the model of most current user interface toolkits to their breaking points.
In addition to contending with advanced expectations from users, developers also have to deal with appearance and behavior guidelines. Most major vendors have begun to specify user interface guidelines that all applications are expected to follow. These guidelines generally take the form of a checklist of rules to which an application must conform. Often, no existing toolkit provides direct support for these rules, because the guidelines were developed independent of, and possibly later than, any available toolkits. For example, the OSF/Motif Style Guide forms the basis of many vendor's user interface standards.The guide specifies that applications should provide context-sensitive on-line help and specifies in some detail how help is supposed to work from a user's perspective. Yet the Motif toolkit provides only rudimentary support for such a system.
Developers who try to conform to the requirements of such style guides often find themselves facing an overwhelming task. Furthermore, asking each individual developer to implement these features from scratch defeats the very purpose of such guidelines. Programmers will inevitably introduce minor variations into each implementation, even if everyone agrees on the interpretation of the rules. Ideally, support for stylistic guidelines should be provided by a user interface toolkit as automatically as possible. Unfortunately, the commonly used piece-meal approach of providing a collection of low-level widgets cannot adequately address this need. Many style issues have broad implications on the architecture and design of applications that individual widgets cannot address.
From a developer's perspective, however, the Motif toolkit offers a programmer's model that has changed little from the earliest user interface toolkits. Applications must construct interfaces from very low-level elements that provide only limited support for tasks applications need to perform. Buttons, scrollbars, and rendering areas represent a necessary and useful minimum feature set for an interactive application. However, the availability of such individual building-blocks falls short of enabling developers to create a complete application. The Motif toolkit provides the raw elements for constructing a user interface. Unfortunately, complete applications require much more than a collection of widgets.
Most application frameworks rely on object-oriented technology to provide as many basic services as possible without limiting the developer's ability to modify the behavior of the basic application model. Because of the way in which frameworks typically work, application frameworks have been described as "upside-down libraries." When using traditional user interface toolkits, applications implement the control flow of the application and call functions provided by the toolkit when various toolkit-level services are needed. In an application framework, a significant portion of the control flow and application-level logic is contained in the library. The library calls functions provided by the application when application-specific behavior is required. Generally, these hooks are supported through the use of inheritance. The framework provides a collection of classes that implement the default behavior expected of all applications. Applications modify these classes to support application-specific behavior by creating subclasses that override the default behavior of the framework, as needed.
One problem with the application framework model is its tendency to be less flexible than the traditional toolkit approach. Any given application framework generally provides strong support for a certain style of application, but provides only weak support for applications that fall outside the domain for which the framework was designed. In the worst case, an application framework's design may interfere with an application's desired behavior.
IRIS ViewKit is written in C++ and provides strong support for an object-oriented application architecture that works well with the Motif toolkit. The ViewKit library supports a strongly stylistic approach to using the Motif widget set, based on the usage patterns of experienced Motif programmers. Developers who are new to Motif programming will find themselves automatically guided to an architectural approach that is straight-forward and flexible, and that supports both small and large applications.
Because IRIS ViewKit emphasizes a particular application architecture, the ViewKit framework is best suited for new development. It may be difficult to move existing applications to IRIS ViewKit, but those beginning new development will find distinct advantages to using the IRIS ViewKit architecture.
Developers who are familiar with C++ will find that IRIS ViewKit offers a familiar and comfortable object-oriented architecture for writing applications while allowing them to take advantage of the standard user interface facilities provided by the Motif library. Programmers who have used the Motif widget set will find that the ViewKit framework performs tasks automatically that they have had to implement themselves in the past.
One of the strengths of the ViewKit library is its support for small details that are often neglected when using the Motif widget set. For example, many applications need to perform certain operations that prevent the application from interacting with the user while the operation is in progress. The accepted behavior in such situations calls for the application to display a busy cursor if the period of time is expected to be brief. For longer periods of time, a dialog may be posted, possibly providing occasional feedback about the progress of the task. In X applications, it is important to also be sure input is blocked during the period in which the application is too busy to handle events. If an application supports multiple windows, input needs to be blocked and a busy cursor displayed in all currently visible windows. Ideally, if the operation is lengthy, the application should allow the user to interrupt the task, as well.
From a user's perspective, such behavior is simply expected. However, when using the Motif toolkit, implementing these features for all situations in which an application may be busy performing some task is sufficiently difficult that many applications do not support this behavior. IRIS ViewKit provides extremely easy-to-use support for such situations. Programmers simply call a function to indicate that the application is entering a busy region and another to indicate when the application is no longer busy. Calls can be nested, and the same function can be used to display an optional status message. The ViewKit framework handles the details of creating busy cursors, displaying them in all windows, disabling input to all windows, creating and displaying dialogs if necessary, and so on. This simple feature alone can save a programmer hours, if not days of work. Allowing operations to be interrupted is trickier, and necessarily requires some cooperation from the developer. However, the ViewKit framework provides as much support as possible to make interruptible operations easy to implement.
IRIS ViewKit coordinates these separate pieces using an integrated set of classes that supports complete SGI-style applications with as little work as possible. For example, even the simplest IRIS ViewKit application is fully integrated with SGI's on-line help system. Programmers do not have to write a single line of code to provide full on-line help for a IRIS ViewKit application. Only the content of the help messages need to be provided.
Figure 1 and Figure 2 illustrate the difference between the architecture of applications developed using the low-level libraries supported on the Silicon Graphics platform and the architecture of an application based on the IRIS ViewKit framework.
Figure 1 . Traditional application architecture.
Figure 2 . The IRIS ViewKit "upside down library" architecture.
The core framework classes also include support for features needed by nearly all applications. These classes include VkApp, an application class that must be instantiated by every IRIS ViewKit application, classes that support top-level windows, a collection of classes that support menus, and several classes that support dialog management. All classes are designed to fully implement as many typical features as possible. For example, all top-level windows and dialogs handle the window manager quit/close protocol. Dialogs are cached to balance memory use and display speed. The menu system goes beyond simply constructing menus to support dynamically adding, removing, replacing items, and more.
The collection of classes that make up the core part of IRIS ViewKit are closely integrated and work together to support essential features required by most applications as automatically as possible. Among the basic services supported by the core ViewKit framework are single and multi-level undo, support for performing interruptible tasks, and support for an application-level callback mechanism that allows C++ classes to dynamically register member functions to be invoked by other C++ classes.
Figure 1 shows a typical IRIS ViewKit high-level component. This component is a self-contained graph editor/viewer that can be used to browse or create an abstract graph representation consisting of a collection of interconnected objects. Nodes in the graph can be moved interactively. The controls along the bottom of the component allow the graph to be zoomed, the orientation to be changed, and other operations to be performed. An overview of the graph can also be displayed for large graphs. Although the component described here represents a complex sub-system, the entire component can be included in an application simply by instantiating a single C++ class, and using the well-defined interface supported by that class.
Figure 3 . A typical high-level IRIS ViewKit component.
Creating high-level components such as the graph viewer shown in Figure 3 promotes consistency throughout a set of applications by providing elements that users can learn once and then easily recognize in multiple applications.
One particularly interesting set of utility classes supports operations on groups of widgets. For example, VkRadioGroup allows an arbitrary collection of Motif toggle buttons to exhibit radio behavior, even if these widgets are in different locations in the interface or widget hierarchy. The VkAlignmentGroup class allows developers to specify a collection of widgets that should be aligned to the same width, height, x, or y position.
IRIS ViewKit supports an easy-to-use collection of classes for building preference panels. Rather than dealing directly with Motif widgets, their placement, callbacks, and so on, programmers who use the ViewKit framework can simply create groups of preference items. These items maintain their own state, which allows an application to simply query each item to see if it has been changed. Layout is handled automatically, and the ViewKit library provides the ability to apply or revert all preferences to their previous state.
IRIS ViewKit supports integration with the ToolTalk service in two ways. First, the ViewKit framework supplies a higher-level, easy-to-use interface to the ToolTalk library that supports a simple callback model, not unlike the Xt callback mechanism. Second, the IRIS ViewKit framework provides various abstract classes that handle many of the details of registering with the message service and handling messages automatically.
The ToolTalk system assumes that messages are handled on an application level (and in fact messages are always sent between processes). However, IRIS ViewKit also supports individual components that need to encapsulate messaging behavior. For example, imagine a component that allows the user to display and edit some data stored in a file. It is easy to imagine multiple applications using this component to browse or edit the same data simultaneously. Using the ToolTalk communication mechanism, the component can transparently coordinate access and display of the data between applications. For example, if the user edits the data in one view, that view can send notices to other instances of the component to keep them in sync. Because this behavior can be encapsulated in a component, applications that use the component can benefit with no effort on the part of the developer.
Figure 4 . Using the ToolTalk mechanism to communicate between processes.
/////////////////////////////////////////////////// // Simplest possible ViewKit application /////////////////////////////////////////////////// #include <Vk/VkApp.h> #include <Vk/VkWindow.h> void main ( int argc, char **argv ) { VkApp *app = new VkApp("Generic", &argc, argv); VkWindow *win = new VkWindow("generic"); win->show(); // Display the window app->run(); // Run the application }The generic application instantiates an application object (VkApp), and a simple top-level window object (VkWindow). After displaying the window, the application runs. Figure 5 shows how the generic application appears on the screen.
Figure 5 . The IRIS ViewKit generic application.
The IRIS ViewKit generic application automatically supports on-line context-sensitive help, has ready-to-use services such as busy cursors and standard dialogs is integrated with the SGI desktop, and includes support for audio. The developer has only to add those elements that are application specific. IRIS ViewKit also makes it easy to extend the generic application to meet application-specific needs.
This program defines some application-specific behavior by subclassing from the VkWindow class provided by the IRIS ViewKit framework. The MyWindow class inherits all the behavior of the VkWindow class, but adds a ViewKit component as a view to be displayed in the window. Subclasses of VkWindow can add any ViewKit component, any application-defined component, or any Motif widget as a view. This example adds an instance of the VkOutline class, which is a simple hierarchy browser included in the ViewKit library. The MyWindow class programmatically adds several items to the hierarchy, and then displays the entire outline.
The main program is similar to the generic application discussed earlier, but instantiates VkMsgApp and MyWindow objects to implement the desired behavior.
/////////////////////////////////////////////////////// // outline: exercise the ViewKit outline component ////////////////////////////////////////////////////// #include <Vk/VkMsgApp.h> #include <Vk/VkWindow.h> #include <Vk/VkOutline.h> class MyWindow : public VkWindow { public: MyWindow(const char *name); }; MyWindow::MyWindow(const char *name) : VkWindow(name) { // Create a VkOutliner component and add it as a view VkOutline *outliner = new VkOutline("outliner", (*this)); addView(outliner); // Construct a hierarchy by adding parent/child pairs outliner->add("Heading 1", "SubHeading 1"); outliner->add("Heading 1", "SubHeading 2"); outliner->add("Heading 1", "SubHeading 3"); outliner->add("SubHeading 1", "Item 1"); outliner->displayAll(); // Show the entire outline } void main ( int argc, char **argv ) { VkMsgApp *app = new VkMsgApp("Outline", &argc, argv); MyWindow *win = new MyWindow("outline"); win->show(); // Display the window app->run(); // Run the application }Figure 6 shows this program as it appears on the screen. The various hierarchy levels can be collapsed or expanded by clicking on the arrows beside each heading.
Figure 6 . IRIS ViewKit application with application-specific behavior.
//////////////////////////////////////////////////////////////// // Code required to add an Application pane containing // a quit action to an existing menubar in an existing // window, using the Motif toolkit. ///////////////////////////////////////////////////////////////// // Add an application pane to the menu pane = XmCreatePulldownMenu(menubar, "application", NULL, 0); // Add a cascade button to the menu pane and attach the pulldown menu pane cascade = XtVaCreateManagedWidget("application", xmCascadeButtonWidgetClass, menubar, XmNsubMenuId, pane, NULL ); // Add a quit item to the pane quitB = XmCreatePushButton(pane, "quit", NULL, 0); XtManageWidget(quitB); // Add a callback to be invoked when the user issues the quit command XtAddCallback(quitB, XmNactivateCallback, safeQuitCallback, NULL);The menu pane and quit entry have now been created, but we still need to implement the safeQuitCallback() function and related facilities. A "safe quit" mechanism could be implemented as follows, using raw Motif:
////////////////////////////////////////////////// // Popup a dialog to ask the user to confirm // a quit command before actually executing it. ////////////////////////////////////////////////// void safeQuitCallback(Widget w, XtPointer, XtPointer) { // Create a dialog Widget dialog = XmCreateQuestionDialog(w, "question", NULL, 0); // Create the message to be displayed XmString xmstr = XmStringCreateLocalized("Do you really want to quit?"); // Set the dialog to display the message XtVaSetValues(dialog, XmNmessageString, xmstr, XmNdialogStyle, XmDIALOG_APPLICATION_MODAL, NULL); // Free the compound string when it is no longer needed XmStringFree(xmstr); // Assign callbacks to be called when the user clicks on OK or Cancel XtAddCallback(dialog, XmNokCallback, reallyQuit, NULL); XtAddCallback(dialog, XmNcancelCallback, cancelCallback, NULL); // Handle the window manager close button Atom WM_DELETE_WINDOW = XInternAtom(XtDisplay(w), "WM_DELETE_WINDOW", FALSE); XmAddWMProtocol(XtParent(dialog), WM_DELETE_WINDOW, cancelCallback, NULL); XtVaSetValues(XtParent(dialog), XmNdeleteResponce, XmDO_NOTHING, NULL); // Display the dialog XtManageChild(dialog); } // This function is called if the user confirms the action void reallyQuit(Widget, XtPointer, XtPointer) { exit(0); } // If the user cancels the action, simply destroy the dialog widget void cancelCallback(Widget w, XtPointer, XtPointer) { XtDestroyWidget(w); }Programmers familiar with the Motif toolkit will recognize these code segments as typical of the level of detail they contend with every day. These code segments implement a single, trivial feature. Most applications support dozens, if not hundreds of such commands, and programmers who work with the Motif widget set or similar toolkits implement this type of feature over and over. The situation is actually worse than it appears, because the code segments shown here cut several corners that would not be acceptable for product-quality applications. For example, this code segment hard-codes the message "Do you really want to quit?" in English, preventing the application from being localized to some other language. The dialog positioning is not handled well, and there is also no provision for providing the same behavior for the quit command that the user can issue from the window manager menu. There is also no supported mechanism to allow other parts of the application to clean up before the program exits. The code simply exits.
IRIS ViewKit improves programmers' productivity dramatically by providing support for such common operations. For example, the following complete program adds the same functionality described above to the IRIS ViewKit generic application, but this time taking advantage of just a few of the IRIS ViewKit facilities.
////////////////////////////////////////////////////////////// // Generic IRIS ViewKit application with a "safe quit" menu item ///////////////////////////////////////////////////////////// #include <Vk/VkApp.h> #include <Vk/VkWindow.h> #include <Vk/VkSubMenu.h> // Provide the function to be executed to really quit void quitCallback(Widget, XtPointer, XtPointer) { theApplication->terminate(0); // Clean shut down function } void main ( int argc, char **argv ) { VkApp *app = new VkApp("Generic", &argc, argv); VkWindow *win = new VkWindow("generic"); // Add a menu pane to the window's menu VkSubMenu *pane = win->addMenuPane("Application"); // Add an item to the pane. Action requires user confirmation first pane->addConfirmFirstAction("Quit", quitCallback, NULL); win->show(); // Display the window app->run(); // Run the application }This is the complete application. The ViewKit implementation not only provides all the capabilities of the substantially lengthier Motif code shown earlier, it does so in a comprehensive, robust, and extensible way. For example, the message displayed in the confirmation dialog can be customized easily. The application can also be easily localized. And of course, like the earlier example, this program supports context-sensitive on-line help and other features automatically.
The first step when developing an object-oriented application based on the ViewKit framework is to identify a set of objects that can be used to construct the program. There are many ways to design an object-oriented system, but one common approach is somewhat analogous to functional decomposition, a common design technique used with traditional programming styles. In functional decomposition, a programmer starts with a single function and breaks it down into multiple functions. The process is usually repeated until many small, easily understood functions have been identified. In object-oriented decomposition, the starting point is a large-scale object that can be broken down into smaller objects. For example, an automobile is an object that contains many smaller objects an engine, a body, a chassis, and so on. These objects can be decomposed further. For example, an engine has valves, pistons, and so on. Programs can usually be organized in a similar way.
A mock-up of the user interface can be a useful place to start the design of an interactive application, because it is common for some parts of a program to correspond to logical groupings of elements of the user interface. For example, Figure 7 shows a proposed user interface for an overly-simplified address book program named rolodex.
Figure 7 . User interface for the rolodex program.
Looking at the proposed rolodex interface, one can observe several logical user interface components. First, it might be useful to encapsulate the entire panel in a class that can be instantiated whenever a rolodex is needed. (The interface in Figure 7 looks like a stand-alone program, but it is easy to imagine an application that might use a rolodex as just one of many useful facilities.) So, it seems reasonable to create a Rolodex class as a ViewKit component.
The Rolodex class can be decomposed further. The screen shows a logical address area, and a command panel along the bottom. These can be implemented as Address and Command classes. The Address object consists of individual labeled text areas, which could each be implemented as a still smaller component, a LabeledText class.
Besides the user interface, there must be some way to store the information associated with the rolodex, so we might create a Database class. It might also be useful to abstract the information stored in the database, so a Record class could be created to represent a single name and address. So, the list of classes that can be used to construct the rolodex program include the Command, Address, LabeledText, Database, and Record classes. All these classes work together to form a subsystem that forms a single logical user interface component, bound together by the Rolodex class.
The next step is to determine the interfaces between the various objects. For the best results, these interfaces should be based on the role the object plays in the system, and have little to do with internal implementation details. For example, the Address class might support member functions for clearing the current display, displaying a new record, and creating a record from the information typed in by a user. The Command object simply sends messages to other objects. For example, the Command object might send a "clear" message to the Address object, an "add" message to the Database object, and so on.
Figure 8 illustrates the architecture of the resulting system, by diagramming the messages that flow between objects in the system. This diagram shows all the classes used in the Rolodex example as boxes. The labeled vectors between the classes indicate member function calls (messages) that could occur between objects instantiated from these classes. Figure 8 clearly shows the relationships between the classes that implement the rolodex user interface component.
Once an initial design has been developed, the individual classes can be implemented. Many of these classes can be implemented as subclasses of the VkComponent class. The modular design makes it easy to extend or modify the system if needed. The new classes will fit smoothly with existing ViewKit classes to form a complete application.
Figure 8 . A message diagram of the rolodex subsystem.
The rolodex program described above provides one example. This simple program could be written in any number of ways. The object-oriented design described above may actually take longer to develop and require more code to implement than some other approaches, although the IRIS ViewKit library will provide a substantial amount of support, which tends to reduce the amount of code to be written. The additional work is a result of the emphasis on clean, abstract interfaces and a well-defined separation of tasks. In return for the additional time spent designing for an object-oriented model, the rolodex example has the potential to yield some new classes that may be reusable in some situations. The Rolodex class is rather specialized, but it could be useful in some applications. The LabeledText class is very simple, but is quite general purpose and could easily be useful elsewhere. The Address class is less task-specific than the Rolodex class, and might also be useful in other situations. Thus, the design of this simple application has resulted in three new, potentially reusable classes, which could be added to the pool of ViewKit-compatible components available to future applications.
IRIS ViewKit supports the creation of such components in several ways. First, the VkComponent class defines a common interface to be supported by all components. As long as user interface components are implemented as subclasses of VkComponent, the ViewKit library provides additional services that can operate on and work with these classes. The VkComponent class also supports C++ member function callbacks, which provides a way for classes to interact with one another without requiring hard-coded dependencies between classes. (Hard-coded dependencies decrease reusability.) Finally, the ViewKit framework provides a core set of services that all components can depend on. Classes can readily use dialogs, the undo facility, and so on, knowing that these core ViewKit facilities will always be available in any IRIS ViewKit application.
A user interface builder allows programmers to draw and test an interface interactively without writing code. In many cases, such tools can have an extremely beneficial effect on a programmers' productivity during the early development and design stages. Most such tools allow a programmer to create an application's interface and then go immediately to a "play" mode, in which the interface responds to user input. Users can press buttons, type in text and so on. By reducing the time a programmer spends compiling and debugging, a builder can greatly reduce the amount of time required to create a first prototype of a user interface. Using a builder allows a programmer to show a realistic prototype of an interface to potential users before committing the design to code. Most such tools can produce code that corresponds to the interactively-developed interface. Since generated code will normally be free of syntax errors, programmers can typically have a running program with a complete user interface after the first compilation.
Not everyone has been successful using user interface builders in the past, largely due to limitations in the technology. Programmers are often disappointed in the code structure produced by builders when generating complete programs. Particularly in C-based programs, it can be difficult to automatically generate code whose structure is appropriate for large systems. Most builders generate code that is incomplete, which also causes problems for programmers working in C. Typically, the code generated by the builder must be modified, which forces the programmer to understand the generated code, and may also prevent the programmer from using the builder for further development or modifications.
The component-based approach supported by the IRIS ViewKit framework is well-suited to an interactive user interface builder, and leads to solutions to some of these problems. First, a builder can be used to create individual user interface components rather than an entire application. A builder can allow IRIS ViewKit components to be created quickly and easily. Because these components tend to be small, functionally cohesive units, the problem of an architecture based on monolithic code segments is avoided. When used in this manner, a builder can actually encourage an object-oriented architecture based on collections of components.
The object-oriented technology used by IRIS ViewKit also provides one solution to the problem of modifying generated code. All classes created by a builder can be treated as abstract base classes, which are never modified. Programmers, of course inevitably need to write some code to connect such classes to the rest of an application. When using the object-oriented approach described here, application-specific code can be added easily by creating subclasses of the generated class and modifying only the derived class. So long as no changes are made to the base class generated by the builder, the class can be reloaded into the builder at any time and modified as needed. Of course, changes made to the base class must be carefully controlled to avoid removing any elements on which derived classes depend.
IRIS ViewKit provides an interactive "builder" solution by coordinating with BuilderXcessory, a Motif user interface builder from Integrated Computer Solutions (ICS). BuilderXcessory supports the concept of C++ components although it does not directly use IRIS ViewKit classes. SGI provides a IRIS ViewKit module that can be added to BuilderXcessory to allow BuilderXcessory to generate IRIS ViewKit-style programs.
///////////////////////////////////////////////////////////////// // Cube.C: Demonstrate a simple use of ViewKit and Inventor ///////////////////////////////////////////////////////////////// #include <Vk/VkInventorApp.h> #include <Vk/VkInventorWindow.h> #include <Inventor/nodes/SoCube.h> void quitCallback(Widget, XtPointer, XtPointer) { theApplication->terminate(0); // Clean shut down function } // Main driver. Just instantiate a VkApp and a viewer, "show" // the viewer and then "run" the application. void main ( int argc, char **argv ) { // Init ViewKit VkApp *app = new VkInventorApp("Cube", &argc, argv); VkInventorWindow *win = new VkInventorWindow( "cube", new SoCube()); // Add a menu pane with one menu item VkSubMenu *pane = win->addMenuPane("Application"); pane->addConfirmFirstAction("Quit", quitCallback, NULL); // Show window and run win->show(); app->run(); }This program just creates an instance of VkInventorApp and an instance of window that creates an Inventor scene viewer an Inventor viewer. A new Inventor object (SoCube) is created and added the scene viewer window.